// bdlb_print.h                                                       -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BDLB_PRINT
#define INCLUDED_BDLB_PRINT

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide platform-independent stream utilities.
//
//@CLASSES:
//  bdlb::Print: namespace for procedures on streams
//  bdlb::PrintStringHexDumper: create/print hex buffers, multi-line
//  bdlb::PrintStringSingleLineHexDumper: create/print hex buffers, single line
//
//@DESCRIPTION: This component provides a namespace, 'bdlb::Print', containing
// utility functions for formatting data to 'bsl::ostream' objects.  These
// functions provide several variations of hexadecimal format, allow
// platform-independent representation of 'void *' pointers, and can help with
// the indentation of hierarchical data.
//
// This component also provides two helper classes,
// 'bdlb::PrintStringHexDumper' and 'bdlb::PrintStringSingleLineHexDumper',
// that define 'operator<<' so they can be used in chains of '<<' operations.
// The 'bdlb::PrintStringHexDumper' class produces formatted, possibly
// multi-line output, whereas the 'bdlb::PrintStringSingleLineHexDumper' class
// produces a simple sequence of hexadecimal digits (and no newline).
//
///'xxd'-Compatible 'hexDump'
/// - - - - - - - - - - - - -
// The output generated by the 'hexDump' functions is not 'xxd'-compatible (see
// 'http://gd.tuwien.ac.at/linuxcommand.org/man_pages/xxd1.html').  The
// following perl script is provided that will convert 'hexDump' output into
// 'xxd'-compatible form.  Run the script with a file containing the 'hexDump'
// output as the first argument.
//..
//  #!/usr/bin/perl -w
//
//  use strict;
//
//  my $num = 0;
//  while (<>) {
//      next if (!$_);
//      my $str = $_;
//      next if !($str =~ s/^[^:]*?:\s*//);
//      my $h = sprintf("%08X",$num);
//      $str =~ s/(\S{4})([\S\W]{4})\s?([\S\W]{4})([\S\W]{4})\s?([\S\W]{4})?
//            ([\S\W]{4})?\s?([\S\W]{4})?([\S\W]{4})?/$1 $2 $3 $4 $5 $6 $7 $8/;
//      $str =~ s/\s \|([^|]+)\|.*$/ $1/;
//      print "$h: ";
//      print $str;
//      $num = $num + 16;
//  }
//..
//
///Usage
///-----
// In this section we show intended usage of this component.
//
///Example 1: Using 'printPtr'
///- - - - - - - - - - - - - -
// The default output produced from pointer values is non-standard across
// vendor platforms.  The 'printPtr' method addresses this inconsistency by
// always producing a consistent format for a given pointer size:
//..
//  const void *a = reinterpret_cast<void *>(0x0);
//  const void *b = reinterpret_cast<void *>(0xf2ff);
//  const void *c = reinterpret_cast<void *>(0x0123);
//  const void *d = reinterpret_cast<void *>(0xf1f2abc9);
//
//  bsl::ostringstream out1;
//
//  bdlb::Print::printPtr(out1, a); out1 << endl;
//  bdlb::Print::printPtr(out1, b); out1 << endl;
//  bdlb::Print::printPtr(out1, c); out1 << endl;
//  bdlb::Print::printPtr(out1, d); out1 << endl;
//
//  assert("0"        "\n"
//         "f2ff"     "\n"
//         "123"      "\n"
//         "f1f2abc9" "\n" == out1.str());
//..
//
///Example 2: Using the Helper Classes
///- - - - - - - - - - - - - - - - - -
// The two helper classes allow users to stream a hexadecimal representation
// of a sequence of bytes into an output stream.
//
// The 'bdlb::PrintStringHexDumper' provides a formatted, possibly multi-line
// representation:
//..
//  char buf[] = "abcdefghijklmnopqrstuvwxyz";
//
//  bsl::ostringstream out2a;
//  out2a << bdlb::PrintStringHexDumper(buf, sizeof buf);
//
//  assert(
//     "     0:   61626364 65666768 696A6B6C 6D6E6F70     |abcdefghijklmnop|\n"
//     "    16:   71727374 75767778 797A00                |qrstuvwxyz.     |\n"
//      == out2a.str());
//
//  bsl::ostringstream out2b;
//  out2b << bdlb::PrintStringSingleLineHexDumper(buf, sizeof buf);
//..
// The 'bdlb::PrintStringSingleLineHexDumper' provides a simple, single-line
// representation.
//..
//  assert("6162636465666768696A6B6C6D6E6F707172737475767778797A00"
//      == out2b.str());
//..

#include <bdlscm_version.h>

#include <bsls_assert.h>
#include <bsls_review.h>

#include <bsl_ostream.h>
#include <bsl_utility.h>

namespace BloombergLP {
namespace bdlb {
                                // ============
                                // struct Print
                                // ============

struct Print {
    // Provide a namespace for the interface to a suite of procedural stream
    // operations.

    // CLASS METHODS
    static bsl::ostream& indent(bsl::ostream& stream,
                                int           level,
                                int           spacesPerLevel = 4);
        // Emit to the specified output 'stream' the number of spaces (' ')
        // equal to the absolute value of the product of the specified 'level'
        // and 'spacesPerLevel' or, if 'level' is negative, nothing at all.
        // Return a reference providing modifiable access to 'stream'.  The
        // behavior is undefined unless the absolute value of the product of
        // the specified 'level' and 'spacesPerLevel' is representable as
        // 'int'.

    static bsl::ostream& newlineAndIndent(bsl::ostream& stream,
                                          int           level,
                                          int           spacesPerLevel = 4);
        // Emit to the specified 'stream' a newline ('\n') followed by the
        // number of spaces (' ') equal to the absolute value of the product
        // of the specified 'level' and 'spacesPerLevel' or, if
        // 'spacesPerLevel' is negative, emit a single space (and *no*
        // newline).  Return a reference providing modifiable access to
        // 'stream'.  The behavior is undefined unless the absolute value of
        // the product of the specified 'level' and 'spacesPerLevel' is
        // representable as 'int'.

    static void printPtr(bsl::ostream& stream, const void *value);
        // Print to the specified 'stream' the specified pointer 'value' in a
        // standard format.  The output is in hexadecimal format with a maximum
        // length of '2 * sizeof(void *)'.  The output does not have leading
        // zeros and is not preceded by '0x'.  The hexadecimal digits ('a' to
        // 'f', inclusive) are expressed in lower case.

    static bsl::ostream& printString(bsl::ostream&  stream,
                                     const char    *string,
                                     int            length,
                                     bool           escapeBackSlash = false);
        // Print to the specified 'stream' the specified 'string' of the
        // specified 'length' and return a reference providing modifiable
        // access to 'stream'.  If the optionally specified 'escapeBackSlash'
        // flag is 'true', then all occurrences of the backslash character
        // ('\') in the 'string' are escaped (i.e., expanded to "\\") when
        // written to the 'stream'.  Note that non-printable characters in
        // 'string' will be printed in their hexadecimal representation
        // ('\xHH').  If 'stream' is not valid on entry, this operation has no
        // effect.  The behavior is undefined unless '0 <= length'.

    static bsl::ostream& hexDump(bsl::ostream&  stream,
                                 const char    *buffer,
                                 int            length);
        // Print in hexadecimal format the contents of the specified 'buffer'
        // of the specified 'length' to the specified 'stream', and return a
        // reference providing modifiable access to 'stream'.  The behavior is
        // undefined unless '0 <= length'.

    static bsl::ostream& hexDump(bsl::ostream&                  stream,
                                 bsl::pair<const char *, int > *buffers,
                                 int                            numBuffers);
        // Print to the specified 'stream' the specified 'numBuffers' buffers
        // supplied by specified 'buffers' in a hexadecimal representation (16
        // chars per line) followed by the ASCII representation.  Return a
        // reference providing modifiable access to 'stream'.  The array of
        // buffers are supplied as a 'bsl::pair<const char*, int> *' where the
        // first element is a pointer to the data, and the second element is
        // the length of the buffer.  The behavior is undefined unless
        // '0 <= numBuffers'.  Note that the contents of the buffers are
        // concatenated and boundaries between buffers are not demarcated.

    template <class INPUT_ITERATOR>
    static bsl::ostream& singleLineHexDump(bsl::ostream&  stream,
                                           INPUT_ITERATOR begin,
                                           INPUT_ITERATOR end);
        // Print to the specified 'stream' the uppercase hex encoding of the
        // byte sequence defined by the specified 'begin' and 'end' iterators
        // of the parameterized 'INPUT_ITERATOR' type, and return a reference
        // providing modifiable access to 'stream'.  Note that 'INPUT_ITERATOR'
        // need not be random-access, i.e., it need support only increment
        // ('++') and equality comparison ('==').  See the non-template version
        // of this function if insulation and/or code bloat are a concern.

    static bsl::ostream& singleLineHexDump(bsl::ostream&  stream,
                                           const char    *begin,
                                           const char    *end);
        // Print to the specified 'stream' the uppercase hex encoding of the
        // byte sequence defined by the specified 'begin' and 'end' iterators
        // into the specified 'stream', and return a reference providing
        // modifiable access to 'stream'.  This function insulates clients from
        // its implementation, but unlike the member template version (above),
        // requires random access iterators of type 'const char *'.  The
        // behavior is undefined unless both 'begin' and 'end' refer to the
        // same block of contiguous memory, and 'begin <= end'.

    static bsl::ostream& singleLineHexDump(bsl::ostream&  stream,
                                           const char    *buffer,
                                           int            length);
        // Print to the specified 'stream' the contents of the specified
        // 'buffer' having the specified 'length' on a single line, and return
        // a reference to the modifiable 'stream'.  The behavior is undefined
        // unless '0 <= length'.
};

                        // ===========================
                        // struct PrintStringHexDumper
                        // ===========================

struct PrintStringHexDumper {
    // Utility for hex dumping a blob to standard output streams.  This class
    // has 'operator<<' defined for it, so it can be used as follows:
    //..
    //  bsl::vector<char> blob;
    //  blob.resize(1024);
    //
    //  // ... fill up the blob with some data ...
    //
    //  bsl::cout << PrintStringHexDumper(blob.data(), blob.size())
    //            << bsl::endl;
    //..

    // DATA
    const char *d_data_p;
    int         d_length;

    // CREATORS
    PrintStringHexDumper(const char *data, int length);
        // Create a 'PrintStringHexDumper' object that can insert to an output
        // stream a formated (possibly multi-lined) hexadecimal representation
        // the specified 'data' of the specified 'length'.
};

// FREE OPERATORS
inline
bsl::ostream& operator<<(bsl::ostream&               stream,
                         const PrintStringHexDumper& rhs);
    // Hex dump the data referenced by the specified 'rhs' to the specified
    // 'stream'.

                   // =====================================
                   // struct PrintStringSingleLineHexDumper
                   // =====================================

struct PrintStringSingleLineHexDumper {
    // Utility for hex dumping a string with no extra formatting to standard
    // output streams.  This class has 'operator<<' defined for it, so it can
    // be used as follows:
    //..
    //  bsl::string str;
    //
    //  // ... fill up the str with some data ...
    //
    //  bsl::cout
    //         << PrintStringSingleLineHexDumper(str.c_str(), str.size())
    //         << bsl::endl;
    //..

    // DATA
    const char *d_data_p;
    int         d_length;

    // CREATORS
    PrintStringSingleLineHexDumper(const char *data, int length);
        // Create a 'PrintStringSingleLineHexDumper' object that can insert to
        // an output stream a single-line hexadecimal representation the
        // specified 'data' of the specified 'length'.
};

// FREE OPERATORS
inline
bsl::ostream& operator<<(bsl::ostream&                         stream,
                         const PrintStringSingleLineHexDumper& rhs);
    // Hex dump the data referenced by the specified 'rhs' to the specified
    // 'stream'.

// ============================================================================
//                        INLINE DEFINITIONS
// ============================================================================

                        // ------------
                        // struct Print
                        // ------------

// CLASS METHODS
template <class INPUT_ITERATOR>
bsl::ostream& Print::singleLineHexDump(bsl::ostream&  stream,
                                       INPUT_ITERATOR begin,
                                       INPUT_ITERATOR end)
{
    enum { k_LOCAL_BUF_SIZE = 512 };
    static const char HEX[] = "0123456789ABCDEF";

    char buf[k_LOCAL_BUF_SIZE];

    unsigned int offset = 0;

    for (; begin != end; ++begin) {

        if (offset >= (k_LOCAL_BUF_SIZE - 1)) {
             stream.write(buf, offset);
             offset = 0;
        }

        const unsigned char c = *begin;

        buf[offset++] = HEX[(c >> 4) & 0xF];
        buf[offset++] = HEX[c        & 0xF];
    }

    if (offset != 0) {
        stream.write(buf, offset);
    }

    return stream;
}

inline
bsl::ostream& Print::singleLineHexDump(bsl::ostream&  stream,
                                       const char    *buffer,
                                       int            length)
{
    BSLS_REVIEW(buffer);
    BSLS_REVIEW(0 <= length);

    return singleLineHexDump(stream, buffer, buffer + length);
}

                        // ---------------------------
                        // struct PrintStringHexDumper
                        // ---------------------------

// CREATORS
inline
PrintStringHexDumper::PrintStringHexDumper(const char *data,
                                           int         length)
: d_data_p(data)
, d_length(length)
{
    BSLS_REVIEW(data);
    BSLS_REVIEW(0 <= length);

}
}  // close package namespace

// FREE OPERATORS
inline
bsl::ostream& bdlb::operator<<(bsl::ostream&               stream,
                               const PrintStringHexDumper& rhs)
{
    return Print::hexDump(stream, rhs.d_data_p, rhs.d_length);
}

namespace bdlb {
                        // -------------------------------------
                        // struct PrintStringSingleLineHexDumper
                        // -------------------------------------

// CREATORS
inline
PrintStringSingleLineHexDumper::PrintStringSingleLineHexDumper(
                                                            const char *data,
                                                            int         length)
: d_data_p(data)
, d_length(length)
{
    BSLS_REVIEW(data);
    BSLS_REVIEW(0 <= length);
}
}  // close package namespace

// FREE OPERATORS
inline
bsl::ostream& bdlb::operator<<(bsl::ostream&                         stream,
                               const PrintStringSingleLineHexDumper& rhs)
{
    return Print::singleLineHexDump(stream, rhs.d_data_p, rhs.d_length);
}

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
